#define _AT25_MODULE_
#include "at25xx.h"

/*****************************************************************************//*!
   *
   * @brief Read data from chip.
   *        
   * @param[in]  Des - destination pointer for receive.
   * @param[in]  Sda - data address in the chip
   * @param[in]  Len - amount of data
   *
   * @return  status.
   *
   * @ Pass/ Fail criteria: none.
   *****************************************************************************/
uint8_t AT25_Read(uint8_t *Des, uint32_t Sda, uint16_t Len)
{
	while((AT25_GetStatus() & AT25_STATUS_WIP_MASK) != 0);
	
	if(0 == Len)
		return 1;
	
	SpiRWSignal(AT25CMD_READ);
	SpiRWSignal((Sda >> 16) & 0xFF);
	SpiRWSignal((Sda >> 8) & 0xFF);
	SpiRWSignal((Sda) & 0xFF);
	SpiRead(Des,Len);
	return 0;
}

/*****************************************************************************//*!
   *
   * @brief Write data to chip.
   *        
   * @param[in]  Src - dest data pointer for writing.
   * @param[in]  Sda - data address in the chip
   * @param[in]  Len - amount of data
   *
   * @return  status.
   *
   * @ Pass/ Fail criteria: none.
   *****************************************************************************/
uint8_t AT25_Write(uint8_t *Src, uint32_t Sda, uint16_t Len)
{

	uint8_t AddrInPage;
	uint16_t LenCur;
	uint16_t LenSave;

	while((AT25_GetStatus() & AT25_STATUS_WIP_MASK) != 0){};       //waiting for chip idle
	
	AddrInPage = Sda % AT25_PAGE_SIZE;
	while(Len > 0)
	{
		while((AT25_GetStatus() & AT25_STATUS_WIP_MASK) != 0){};  //waiting for chip idle
		AT25_WriteEnable();
		
		LenCur  = AT25_PAGE_SIZE - AddrInPage;
		if(LenCur > Len)
			LenCur = Len;
		Len -= LenCur;
		
		LenSave = LenCur;

		SpiRWSignal(AT25CMD_WRITE);
		SpiRWSignal((Sda >> 16) & 0xFF);
		SpiRWSignal((Sda >> 8) & 0xFF);
		SpiRWSignal((Sda) & 0xFF);
		AddrInPage = 0;
		while(LenCur--)
			SpiRWSignal(*Src++);

		SPI_SS_DISABLE();	
		
		AddrInPage = 0;
		Sda += LenSave;

	}

	while((AT25_GetStatus() & AT25_STATUS_WIP_MASK) != 0){};       //waiting for chip idle
 	AT25_WriteDisable();
	return 0;
}

/*****************************************************************************//*!
   *
   * @brief Enable chip protect.
   *        
   * @param[in]  none.
   *
   * @return  status.
   *
   * @ Pass/ Fail criteria: none.
   *****************************************************************************/
uint8_t AT25_WriteEnable(void)
{
	SpiRWSignal(AT25CMD_WREN);
	SPI_SS_DISABLE();
	
	return AT25_GetStatus();
}

/*****************************************************************************//*!
   *
   * @brief Disable chip protect.
   *        
   * @param[in]  none.
   *
   * @return  status.
   *
   * @ Pass/ Fail criteria: none.
   *****************************************************************************/
uint8_t AT25_WriteDisable(void)
{
	SpiRWSignal(AT25CMD_WTDI);
	SPI_SS_DISABLE();
	
	return AT25_GetStatus();
}

/*****************************************************************************//*!
   *
   * @brief Read status.
   *        
   * @param[in]  none.
   *
   * @return  status.
   *
   * @ Pass/ Fail criteria: none.
   *****************************************************************************/
uint8_t AT25_GetStatus(void)
{
	uint8_t Status;
	SpiRWSignal(AT25CMD_RDSR);
	Status = SpiRWSignal(0x55);
	SPI_SS_DISABLE();
	return Status;
}

/*****************************************************************************//*!
   *
   * @brief Write status.
   *        
   * @param[in]  none.
   *
   * @return  status.
   *
   * @ Pass/ Fail criteria: none.
   *****************************************************************************/
uint8_t AT25_SetStatus(uint8_t Status)
{
	SpiRWSignal(AT25CMD_WRSR);
	SpiRWSignal(Status);
	SPI_SS_DISABLE();

	return AT25_GetStatus();
}

/*****************************************************************************//*!
   *
   * @brief Erase page.
   *        
   * @param[in]  Sda - page address.
   *
   * @return  status.
   *
   * @ Pass/ Fail criteria: none.
   *****************************************************************************/
uint8_t AT25_PageErase(uint32_t Sda)
{
	while((AT25_GetStatus() & AT25_STATUS_WIP_MASK) != 0);
	AT25_WriteEnable();
	SpiRWSignal(AT25CMD_PAGE_ERASE);
	SpiRWSignal((Sda >> 16) & 0xFF);
	SpiRWSignal((Sda >> 8) & 0xFF);
	SpiRWSignal((Sda) & 0xFF);
	SPI_SS_DISABLE();

	return AT25_GetStatus();
}

/*****************************************************************************//*!
   *
   * @brief Erase sector.
   *        
   * @param[in]  Sda - sector address.
   *
   * @return  status.
   *
   * @ Pass/ Fail criteria: none.
   *****************************************************************************/
uint8_t AT25_SectorErase(uint32_t Sda)
{
	while((AT25_GetStatus() & AT25_STATUS_WIP_MASK) != 0);
	AT25_WriteEnable();
	SpiRWSignal(AT25CMD_SECTOR_ERASE);
	SpiRWSignal((Sda >> 16) & 0xFF);
	SpiRWSignal((Sda >> 8) & 0xFF);
	SpiRWSignal((Sda) & 0xFF);
	SPI_SS_DISABLE();
	
	return AT25_GetStatus();
}

/*****************************************************************************//*!
   *
   * @brief SPI init.
   *        
   * @param[in]  none.
   *
   * @return  status.
   *
   * @ Pass/ Fail criteria: none.
   *****************************************************************************/
uint8_t AT25_ChipErase(void)
{
	while((AT25_GetStatus() & AT25_STATUS_WIP_MASK) != 0);
	AT25_WriteEnable();
	SpiRWSignal(AT25CMD_CHIP_ERASE);
	SPI_SS_DISABLE();
	
	return AT25_GetStatus();
}

